package main

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/fatih/color"
	"github.com/steveyegge/beads/internal/storage"
)

// runContributorWizard guides the user through OSS contributor setup
func runContributorWizard(ctx context.Context, store storage.Storage) error {
	green := color.New(color.FgGreen).SprintFunc()
	cyan := color.New(color.FgCyan).SprintFunc()
	yellow := color.New(color.FgYellow).SprintFunc()
	bold := color.New(color.Bold).SprintFunc()

	fmt.Printf("\n%s %s\n\n", bold("bd"), bold("Contributor Workflow Setup Wizard"))
	fmt.Println("This wizard will configure beads for OSS contribution.")
	fmt.Println()

	// Step 1: Detect fork relationship
	fmt.Printf("%s Detecting git repository setup...\n", cyan("▶"))

	isFork, upstreamURL := detectForkSetup()

	if isFork {
		fmt.Printf("%s Detected fork workflow (upstream: %s)\n", green("✓"), upstreamURL)
	} else {
		fmt.Printf("%s No upstream remote detected\n", yellow("⚠"))
		fmt.Println("\n  For fork workflows, add an 'upstream' remote:")
		fmt.Println("  git remote add upstream <original-repo-url>")
		fmt.Println()

		// Ask if they want to continue anyway
		fmt.Print("Continue with contributor setup? [y/N]: ")
		reader := bufio.NewReader(os.Stdin)
		response, _ := reader.ReadString('\n')
		response = strings.TrimSpace(strings.ToLower(response))

		if response != "y" && response != "yes" {
			fmt.Println("Setup canceled.")
			return nil
		}
	}

	// Step 2: Check push access to origin
	fmt.Printf("\n%s Checking repository access...\n", cyan("▶"))

	hasPushAccess, originURL := checkPushAccess()

	if hasPushAccess {
		fmt.Printf("%s You have push access to origin (%s)\n", green("✓"), originURL)
		fmt.Printf("  %s You can commit directly to this repository.\n", yellow("⚠"))
		fmt.Println()
		fmt.Print("Do you want to use a separate planning repo anyway? [Y/n]: ")
		reader := bufio.NewReader(os.Stdin)
		response, _ := reader.ReadString('\n')
		response = strings.TrimSpace(strings.ToLower(response))

		if response == "n" || response == "no" {
			fmt.Println("\nSetup canceled. Your issues will be stored in the current repository.")
			return nil
		}
	} else {
		fmt.Printf("%s Read-only access to origin (%s)\n", green("✓"), originURL)
		fmt.Println("  Planning repo recommended to keep experimental work separate.")
	}

	// Step 3: Configure planning repository
	fmt.Printf("\n%s Setting up planning repository...\n", cyan("▶"))

	homeDir, err := os.UserHomeDir()
	if err != nil {
		return fmt.Errorf("failed to get home directory: %w", err)
	}

	defaultPlanningRepo := filepath.Join(homeDir, ".beads-planning")

	fmt.Printf("\nWhere should contributor planning issues be stored?\n")
	fmt.Printf("Default: %s\n", cyan(defaultPlanningRepo))
	fmt.Print("Planning repo path [press Enter for default]: ")

	reader := bufio.NewReader(os.Stdin)
	planningPath, _ := reader.ReadString('\n')
	planningPath = strings.TrimSpace(planningPath)

	if planningPath == "" {
		planningPath = defaultPlanningRepo
	}

	// Expand ~ if present
	if strings.HasPrefix(planningPath, "~/") {
		planningPath = filepath.Join(homeDir, planningPath[2:])
	}

	// Create planning repository if it doesn't exist
	if _, err := os.Stat(planningPath); os.IsNotExist(err) {
		fmt.Printf("\nCreating planning repository at %s\n", cyan(planningPath))

		if err := os.MkdirAll(planningPath, 0750); err != nil {
			return fmt.Errorf("failed to create planning repo directory: %w", err)
		}

		// Initialize git repo in planning directory
		cmd := exec.Command("git", "init")
		cmd.Dir = planningPath
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("failed to initialize git in planning repo: %w", err)
		}

		// Initialize beads in planning repo
		beadsDir := filepath.Join(planningPath, ".beads")
		if err := os.MkdirAll(beadsDir, 0750); err != nil {
			return fmt.Errorf("failed to create .beads in planning repo: %w", err)
		}

		// Create issues.jsonl
		jsonlPath := filepath.Join(beadsDir, "beads.jsonl")
		// #nosec G306 -- planning repo JSONL must be shareable across collaborators
		if err := os.WriteFile(jsonlPath, []byte{}, 0644); err != nil {
			return fmt.Errorf("failed to create issues.jsonl: %w", err)
		}

		// Create README in planning repo
		readmePath := filepath.Join(planningPath, "README.md")
		readmeContent := fmt.Sprintf(`# Beads Planning Repository

This repository stores contributor planning issues for OSS projects.

## Purpose

- Keep experimental planning separate from upstream PRs
- Track discovered work and implementation notes
- Maintain private todos and design exploration

## Usage

Issues here are automatically created when working on forked repositories.

Created by: bd init --contributor
`)
		// #nosec G306 -- README should be world-readable
		if err := os.WriteFile(readmePath, []byte(readmeContent), 0644); err != nil {
			fmt.Fprintf(os.Stderr, "Warning: failed to create README: %v\n", err)
		}

		// Initial commit in planning repo
		cmd = exec.Command("git", "add", ".")
		cmd.Dir = planningPath
		_ = cmd.Run()

		cmd = exec.Command("git", "commit", "-m", "Initial commit: beads planning repository")
		cmd.Dir = planningPath
		_ = cmd.Run()

		fmt.Printf("%s Planning repository created\n", green("✓"))
	} else {
		fmt.Printf("%s Using existing planning repository\n", green("✓"))
	}

	// Step 4: Configure contributor routing
	fmt.Printf("\n%s Configuring contributor auto-routing...\n", cyan("▶"))

	// Set contributor.planning_repo config
	if err := store.SetConfig(ctx, "contributor.planning_repo", planningPath); err != nil {
		return fmt.Errorf("failed to set planning repo config: %w", err)
	}

	// Set contributor.auto_route to true
	if err := store.SetConfig(ctx, "contributor.auto_route", "true"); err != nil {
		return fmt.Errorf("failed to enable auto-routing: %w", err)
	}

	fmt.Printf("%s Auto-routing enabled\n", green("✓"))

	// Step 5: Summary
	fmt.Printf("\n%s %s\n\n", green("✓"), bold("Contributor setup complete!"))

	fmt.Println("Configuration:")
	fmt.Printf("  Current repo issues: %s\n", cyan(".beads/beads.jsonl"))
	fmt.Printf("  Planning repo issues: %s\n", cyan(filepath.Join(planningPath, ".beads/beads.jsonl")))
	fmt.Println()
	fmt.Println("How it works:")
	fmt.Println("  • Issues you create will route to the planning repo")
	fmt.Println("  • Planning stays out of your PRs to upstream")
	fmt.Println("  • Use 'bd list' to see issues from both repos")
	fmt.Println()
	fmt.Printf("Try it: %s\n", cyan("bd create \"Plan feature X\" -p 2"))
	fmt.Println()

	return nil
}

// detectForkSetup checks if we're in a fork by looking for upstream remote
func detectForkSetup() (isFork bool, upstreamURL string) {
	cmd := exec.Command("git", "remote", "get-url", "upstream")
	output, err := cmd.Output()
	if err != nil {
		// No upstream remote found
		return false, ""
	}

	upstreamURL = strings.TrimSpace(string(output))
	return true, upstreamURL
}

// checkPushAccess determines if we have push access to origin
func checkPushAccess() (hasPush bool, originURL string) {
	// Get origin URL
	cmd := exec.Command("git", "remote", "get-url", "origin")
	output, err := cmd.Output()
	if err != nil {
		return false, ""
	}

	originURL = strings.TrimSpace(string(output))

	// SSH URLs indicate likely push access (git@github.com:...)
	if strings.HasPrefix(originURL, "git@") {
		return true, originURL
	}

	// HTTPS URLs typically indicate read-only clone
	if strings.HasPrefix(originURL, "https://") {
		return false, originURL
	}

	// Other protocols (file://, etc.) assume push access
	return true, originURL
}
